package com.qf.common.redis.utils;

import com.qf.common.core.utils.ApplicationUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Slf4j
public class LockUtils {

    private static RedissonClient redissonClient;

    static {
        redissonClient = ApplicationUtils.getBean(RedissonClient.class);
    }

    /**
     * 加锁
     * @param key
     */
    public static boolean lock(String key){
        log.info("[get-lock] - 尝试获取分布式锁 - {}", key);
        RLock lock = redissonClient.getLock(key);
        //设计获取锁的自旋
        while(!lock.tryLock()){}
        //说明获得分布式锁
        LockThreadLocal.setLock(lock);
        log.info("[get-lock] - 成功获得分布式锁 - {}", key);
        return true;
    }

    /**
     * 加锁 - 设置过期时间（单位时间内没有获得锁，就返回false）
     * @param key
     * @param time
     * @param unit
     * @return
     */
    public static boolean lockTimeout(String key, long time, TimeUnit unit){
        log.info("[get-lock] - 尝试获取分布式锁 - {}", key);
        RLock lock = redissonClient.getLock(key);
        //设计获取锁的自旋
        boolean flag = false;
        try {
            flag = lock.tryLock(time, unit);
            if (flag)  LockThreadLocal.setLock(lock);
        } catch (InterruptedException e) {
            log.error("[get-lock] - 获取分布式锁异常", e);
        }
        //说明获得分布式锁
        log.info("[get-lock] - 成功获得分布式锁 - {}", flag);
        return flag;
    }

    /**
     * 解锁
     */
    public static void unlock(){
        log.info("[unlock] - 解除分布式锁");
        RLock lock = LockThreadLocal.getLock();
        //清空ThreadLocal
        LockThreadLocal.clear();
        if(lock != null && lock.isLocked()){
            lock.unlock();
        }
    }

    /**
     * 开启事务锁的入口
     * @return
     */
    public static TransactionLock transactionLock(String lockKey){
        //开启分布式锁
        LockUtils.lock(lockKey);
        return new TransactionLock();
    }

    /**
     * 事务锁类
     */
    public static class TransactionLock {

        private TransactionLock(){}

        private static DataSourceTransactionManager transactionManager;

        static {
            transactionManager = ApplicationUtils.getBean(DataSourceTransactionManager.class);
        }

        //事务状态
        private TransactionStatus status;

        /**
         * 开启事务
         * @return
         */
        public TransactionLock start(){
            DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
            transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            //手动开启一个新事务
            status = transactionManager.getTransaction(transactionDefinition);
            return this;
        }

        /**
         * 执行核心业务（放在事务中）
         */
        public <T> T exec(Supplier<T> supplier){
            T result = null;
            try {
                //执行传递过来的业务
                result = supplier.get();
                //提交事务
                if (status != null) {
                    transactionManager.commit(status);
                }
            } catch (Exception e) {
                log.error("[lock-exception] - 锁中业务的异常", e);
                //回滚事务
                if (status != null) {
                    transactionManager.rollback(status);
                }
            } finally {
                //释放分布式锁
                LockUtils.unlock();
            }
            return result;
        }
    }
}
